package cmpe451.group7.ourcity.beans;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;

import org.apache.commons.lang3.StringUtils;
import org.json.simple.JSONObject;
import org.primefaces.event.FileUploadEvent;
import org.primefaces.event.map.OverlaySelectEvent;
import org.primefaces.model.UploadedFile;
import org.primefaces.model.map.DefaultMapModel;
import org.primefaces.model.map.LatLng;
import org.primefaces.model.map.MapModel;
import org.primefaces.model.map.Marker;

import cmpe451.group7.ourcity.dao.CommentDAO;
import cmpe451.group7.ourcity.dao.MultimediaDAO;
import cmpe451.group7.ourcity.dao.PlaceDAO;
import cmpe451.group7.ourcity.dao.TagDAO;
import cmpe451.group7.ourcity.dao.UserDAO;
import cmpe451.group7.ourcity.entity.Comment;
import cmpe451.group7.ourcity.entity.Multimedia;
import cmpe451.group7.ourcity.entity.MultimediaType;
import cmpe451.group7.ourcity.entity.Place;
import cmpe451.group7.ourcity.entity.Tag;
import cmpe451.group7.ourcity.entity.User;
import cmpe451.group7.ourcity.recommendation.FreebaseQuery;
import cmpe451.group7.ourcity.service.CommentService;
import cmpe451.group7.ourcity.service.PlaceService;
import cmpe451.group7.ourcity.service.UserService;
import cmpe451.group7.ourcity.util.GlobalVariables;
import cmpe451.group7.ourcity.util.Utils;

/**
 * Search bean for using in the search page of the web site.
 */
@ManagedBean
@ViewScoped
public class ViewCommentBean implements Serializable {

	@ManagedProperty(value = "#{loginBean}")
	private LoginBean loginBean;

	@ManagedProperty(value = "#{commentService}")
	private CommentService commentService;

	@ManagedProperty(value = "#{userService}")
	private UserService userService;

	@ManagedProperty(value = "#{multimediaDAO}")
	private MultimediaDAO multimediaDAO;

	@ManagedProperty(value = "#{tagDAO}")
	private TagDAO tagDAO;

	@ManagedProperty(value = "#{placeDAO}")
	private PlaceDAO placeDAO;

	@ManagedProperty(value = "#{commentDAO}")
	private CommentDAO commentDAO;

	@ManagedProperty(value = "#{userDAO}")
	private UserDAO userDAO;

	@ManagedProperty(value = "#{placeService}")
	private PlaceService placeService;

	private static final long serialVersionUID = 1L;

	private String commentIdValue;

	private MapModel map = new DefaultMapModel();
	private Comment comment;
	private User commentUser;
	private Place place;
	private int commentId;
	private Marker marker;
	private boolean myComment;

	// for adding videos to the system
	private String videoURL;

	// for adding audio to the system
	private String audioURL;
	private String audioTitle;

	private User currentUser;

	public ViewCommentBean() {
		super();

		Map<String, String> requestParameterMap = FacesContext
				.getCurrentInstance().getExternalContext()
				.getRequestParameterMap();

		if (requestParameterMap.keySet().size() > 1) {
			// TODO: error correction here
		}

		setCommentId(-1);

		try {
			setCommentIdValue(requestParameterMap.get("commentId"));
			if (getCommentIdValue() == null)
				Utils.redirectPage("search.xhtml");

			setCommentId(Integer.parseInt(getCommentIdValue()));
		} catch (NumberFormatException e) {
			try {
				Utils.redirectPage("search.xhtml");
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	@PostConstruct
	public void init() {
		setComment(commentService
				.findAndFillTagsAndMultimediaId(getCommentId()));

		if (loginBean != null && loginBean.isLoggedIn()) {
			currentUser = userService.fullyLoadUser(loginBean.getUserID());
		}

		setCommentUser(userDAO.findByID(comment.getUser().getUserID()));

		setMyComment(false);

		if (commentUser.equals(currentUser)) {
			setMyComment(true);
		}

		setPlace(placeDAO.findByID(getComment().getPlace().getPlaceID()));

		if (getPlace() != null && getPlace().getLatitude() != 0
				&& getPlace().getLongitude() != 0) {
			// TODO: error correction here
			map.addOverlay(new Marker(new LatLng(getPlace().getLatitude(),
					getPlace().getLongitude()), getPlace().getPlaceName()));
		}

	}

	public List<Tag> completeTags(String query) {
		return FreebaseQuery.completeTags(query);
	}

	public LoginBean getLoginBean() {
		return loginBean;
	}

	public void setLoginBean(LoginBean loginBean) {
		this.loginBean = loginBean;
	}

	/**
	 * Upload an image for the comment
	 * 
	 * @param event
	 */
	public void handleFileUpload(FileUploadEvent event) {
		UploadedFile file = event.getFile();
		FacesMessage msg = null;

		Multimedia image = null;
		image = multimediaDAO.createMultimedia(currentUser, file.getContents(),
				file.getContentType(), MultimediaType.IMAGE);

		if (image != null) {
			getComment().addMultimedia(image);
			getCommentDAO().saveOrUpdate(getComment());

			String messageText = String.format(
					"%s (size:%d) is uploaded.\nContent type:%s",
					file.getFileName(), file.getSize(), file.getContentType());
			msg = new FacesMessage("Succesful", messageText);
		} else {
			String messageText = String.format(
					"Error occured while persisting %s (size:%d)",
					file.getFileName(), file.getSize());
			msg = new FacesMessage("Failure", messageText);
		}
		displayMessage(msg);
	}

	/**
	 * Upload the YouTube url to the system
	 */
	public void addVideoURL() {
		if (StringUtils.isEmpty(videoURL)) {
			displayMessage(new FacesMessage("Failure",
					"Empty video url is given."));
			videoURL = null;
			return;
		}

		JSONObject videoProperties = Utils.youtubeVideoProperties(videoURL);
		if (videoProperties == null) {
			displayMessage(new FacesMessage("Failure",
					"Invalıd video url is given."));
			videoURL = null;
			return;
		}

		Multimedia video = new Multimedia();
		video.setMultimediaType(MultimediaType.VIDEO);
		video.setPath(videoURL);
		video.setTitle((String) videoProperties.get("title"));
		video.setOwner(currentUser);

		multimediaDAO.save(video);

		getComment().addMultimedia(video);
		commentDAO.update(getComment());

		displayMessage(new FacesMessage("Successful",
				"Video url is successfully added."));

		videoURL = null;
	}

	/**
	 * Add a Vocaroo.com url to the comment
	 */
	public void addAudioURL() {
		if (StringUtils.isEmpty(audioURL)) {
			displayMessage(new FacesMessage("Failure",
					"Empty audio url is given."));
			return;
		}

		audioURL = audioURL.trim();

		boolean isValidAudioURL = GlobalVariables.audioURLPattern.matcher(
				audioURL).find();

		if (!isValidAudioURL) {
			displayMessage(new FacesMessage("Failure",
					"Invalıd audio url is given."));
			return;
		}

		Matcher matcher = GlobalVariables.audioIdPattern.matcher(audioURL);
		matcher.find();
		String audioPath = matcher.group(1);

		Multimedia audio = new Multimedia();
		audio.setMultimediaType(MultimediaType.AUDIO);
		audio.setPath(audioPath);
		audio.setTitle(audioTitle);
		audio.setOwner(currentUser);

		multimediaDAO.save(audio);

		getComment().addMultimedia(audio);
		commentDAO.update(getComment());

		displayMessage(new FacesMessage("Successful",
				"Audio url is successfully added."));

		audioURL = videoURL = null;
	}

	public List<Multimedia> getMediaList() {
		return new ArrayList<Multimedia>(getComment().getMultimedia());
	}

	/* getters & setters */

	public void displayMessage(FacesMessage message) {
		FacesContext.getCurrentInstance().addMessage(null, message);
	}

	public MapModel getMap() {
		return map;
	}

	public void setMap(MapModel map) {
		this.map = map;
	}

	public void onMarkerSelect(OverlaySelectEvent event) {
		marker = (Marker) event.getOverlay();
	}

	public Marker getMarker() {
		return marker;
	}

	public MultimediaDAO getMultimediaDAO() {
		return multimediaDAO;
	}

	public void setMultimediaDAO(MultimediaDAO multimediaDAO) {
		this.multimediaDAO = multimediaDAO;
	}

	public CommentService getCommentService() {
		return commentService;
	}

	public void setCommentService(CommentService commentService) {
		this.commentService = commentService;
	}

	public PlaceService getPlaceService() {
		return placeService;
	}

	public void setPlaceService(PlaceService placeService) {
		this.placeService = placeService;
	}

	public TagDAO getTagDAO() {
		return tagDAO;
	}

	public void setTagDAO(TagDAO tagDAO) {
		this.tagDAO = tagDAO;
	}

	public PlaceDAO getPlaceDAO() {
		return placeDAO;
	}

	public void setPlaceDAO(PlaceDAO placeDAO) {
		this.placeDAO = placeDAO;
	}

	public String getVideoURL() {
		return videoURL;
	}

	public void setVideoURL(String videoURL) {
		this.videoURL = videoURL;
	}

	public String getAudioURL() {
		return audioURL;
	}

	public void setAudioURL(String audioURL) {
		this.audioURL = audioURL;
	}

	public String getAudioTitle() {
		return audioTitle;
	}

	public void setAudioTitle(String audioTitle) {
		this.audioTitle = audioTitle;
	}

	public UserService getUserService() {
		return userService;
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	public CommentDAO getCommentDAO() {
		return commentDAO;
	}

	public void setCommentDAO(CommentDAO commentDAO) {
		this.commentDAO = commentDAO;
	}

	public Comment getComment() {
		return comment;
	}

	public void setComment(Comment comment) {
		this.comment = comment;
	}

	public Place getPlace() {
		return place;
	}

	public void setPlace(Place place) {
		this.place = place;
	}

	public int getCommentId() {
		return commentId;
	}

	public void setCommentId(int commentId) {
		this.commentId = commentId;
	}

	public String getCommentIdValue() {
		return commentIdValue;
	}

	public void setCommentIdValue(String commentIdValue) {
		this.commentIdValue = commentIdValue;
	}

	public UserDAO getUserDAO() {
		return userDAO;
	}

	public void setUserDAO(UserDAO userDAO) {
		this.userDAO = userDAO;
	}

	public User getCommentUser() {
		return commentUser;
	}

	public void setCommentUser(User commentUser) {
		this.commentUser = commentUser;
	}

	public boolean isMyComment() {
		return myComment;
	}

	public void setMyComment(boolean myComment) {
		this.myComment = myComment;
	}

}
